package com.jiahe.blog.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jiahe.blog.common.exception.BlogException;
import com.jiahe.blog.dao.UserAuthDao;
import com.jiahe.blog.dao.UserInfoDao;
import com.jiahe.blog.dao.UserRoleDao;
import com.jiahe.blog.entity.UserAuthEntity;
import com.jiahe.blog.entity.UserInfoEntity;
import com.jiahe.blog.entity.UserRoleEntity;
import com.jiahe.blog.model.BlogConst;
import com.jiahe.blog.model.MQPrefixConst;
import com.jiahe.blog.model.RedisPrefixConst;
import com.jiahe.blog.model.dto.EmailDTO;
import com.jiahe.blog.model.dto.PageDTO;
import com.jiahe.blog.model.dto.UserBackDTO;
import com.jiahe.blog.model.dto.UserInfoDTO;
import com.jiahe.blog.model.enums.LoginTypeEnum;
import com.jiahe.blog.model.enums.RoleEnum;
import com.jiahe.blog.model.vo.ConditionVO;
import com.jiahe.blog.model.vo.UserVO;
import com.jiahe.blog.service.UserAuthService;
import com.jiahe.blog.utils.CommonUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class UserAuthServiceImpl extends ServiceImpl<UserAuthDao, UserAuthEntity> implements UserAuthService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private UserAuthDao userAuthDao;

    @Autowired
    private UserInfoDao userInfoDao;

    @Autowired
    private UserRoleDao userRoleDao;

    @Override
    public void sendCode(String username) {
        // 校验账号是否合法
        if (!CommonUtils.checkEmail(username)) {
            throw new BlogException("邮箱格式不正确");
        }
        // 生成六位随机验证码发送
        StringBuilder code = getCode();
        // 发送验证码
        EmailDTO email = EmailDTO.builder()
                .email(username)
                .subject("验证码")
                .content("【JiaHeStudy】 您的验证码为 " + code.toString() + " 有效期15分钟，请不要告诉他人哦")
                .build();
        rabbitTemplate.convertAndSend(MQPrefixConst.EMAIL_EXCHANGE, "*", new Message(JSON.toJSONBytes(email), new MessageProperties()));
        // 将验证码存入redis ，设置过期时间为15分钟
        redisTemplate.boundValueOps(RedisPrefixConst.CODE_KEY + username).set(code);
        redisTemplate.expire(RedisPrefixConst.CODE_KEY + username, RedisPrefixConst.CODE_EXPIRE_TIME, TimeUnit.MILLISECONDS);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveUser(UserVO user) {
        // 校验账号是否合法
        if (checkUser(user)) {
            throw new BlogException("邮箱已被注册");
        }
        //新增用户信息
        UserInfoEntity userInfoEntity = UserInfoEntity.builder()
                .email(user.getUsername())
                .nickname(BlogConst.DEFAULT_NICKNAME)
                .avatar(BlogConst.DEFAULT_AVATAR)
                .createTime(new Date())
                .updateTime(new Date())
                .build();
        userInfoDao.insert(userInfoEntity);
        //绑定用户角色
        saveUserRole(userInfoEntity);
        // 新增用户账号
        UserAuthEntity userAuthEntity = UserAuthEntity.builder()
                .userInfoId(userInfoEntity.getId())
                .username(user.getUsername())
                .password(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()))
                .loginType(LoginTypeEnum.EMAIL.getType())
                .createTime(new Date())
                .build();
        userAuthDao.insert(userAuthEntity);
    }

    @Override
    public UserInfoDTO qqLogin(String openId, String accessToken) {
        return null;
    }

    @Override
    public UserInfoDTO weiBoLogin(String code) {
        return null;
    }

    @Override
    public void updatePassword(UserVO user) {

    }

    @Override
    public PageDTO<UserBackDTO> listUserBackDTO(ConditionVO condition) {
        return null;
    }

    /**
     * 绑定角色
     * @param userInfoEntity 用户信息
     */
    private void saveUserRole(UserInfoEntity userInfoEntity) {
        UserRoleEntity userRoleEntity = UserRoleEntity.builder()
                .userId(userInfoEntity.getId())
                .roleId(RoleEnum.USER.getRoleId())
                .build();
        userRoleDao.insert(userRoleEntity);
    }

    /**
     * 校验用户数据是否合法
     *
     * @param userVO 用户数据
     * @return 合法状态
     */
    private Boolean checkUser(UserVO userVO) {
        // 获取redis中存储的验证码code
        String code =(String) redisTemplate.boundValueOps(RedisPrefixConst.CODE_KEY + userVO.getUsername()).get();
        if (!userVO.getCode().equals(code)) {
            throw new BlogException("验证码错误！");
        }
        // 查询用户名是否存在
        UserAuthEntity authEntity = userAuthDao.selectOne(new LambdaQueryWrapper<UserAuthEntity>()
                .select(UserAuthEntity::getUsername)
                .eq(UserAuthEntity::getUsername, userVO.getUsername()));
        return Objects.nonNull(authEntity);
    }

    /**
     * 获取验证码
     * @return 验证码
     */
    private StringBuilder getCode() {
        StringBuilder code = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        return code;
    }

}
